package yhao.demo.autocode.core.project;

import org.apache.commons.lang3.StringUtils;
import yhao.demo.autocode.core.AutoCodeUtils;
import yhao.infra.common.util.CommonMapUtil;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static yhao.demo.autocode.core.project.NewProjectUtil.packageToPath;
import static yhao.demo.autocode.core.project.NewProjectUtil.rootSrcPath;
import static yhao.demo.autocode.core.project.NewProjectUtil.wordFirstUp;

public class NewWebProjectHelper {

    //项目名
    private String projectName;
    //业务线名，该项可不填
    private String bizName;
    //服务名
    private String webName;

    private boolean needDubbo;
    private boolean needRedis;
    private boolean needActivemq;
    private boolean needRabbitmq;
    private boolean needAuth;

    private String webDir;
    private String rootWebDirPath;
    private String groupId;
    private String rootPackage;

    public final static String CONF_DIR_PATH =
            System.getProperty("user.home") + File.separator + "yhao.newproject";

    /**
     * @param projectName 项目名
     * @param bizName     业务线名
     * @param webName 服务模块名
     * @param packagePrefix 包名前缀
     */
    public NewWebProjectHelper(String projectName, String bizName, String webName,String packagePrefix) {
        this.projectName = projectName;
        this.bizName = bizName;
        this.webName = webName;
        if(StringUtils.isEmpty(projectName) || StringUtils.isEmpty(webName) ){
            throw new RuntimeException("projectName或webName不得为空");
        }
        groupId = String.format("%s.%sweb",projectName,(StringUtils.isNotEmpty(bizName)?bizName+".":""));
        rootPackage = (StringUtils.isEmpty(packagePrefix)?"":packagePrefix+".")+groupId + "." + webName;
        webDir = "web" + (StringUtils.isNotEmpty(bizName)?("-"+bizName):"")+"-"+webName;
        rootWebDirPath = CONF_DIR_PATH + File.separator + webDir;
    }

    public void doNew() throws IOException {
        System.out.println(toString());
        System.out.println("开始生成项目文件...");

        System.out.println("开始生成根目录...");
        makeRoot();
        System.out.println("开始生成根目录...DONE");

        System.out.println("开始生成代码文件...");
        makeWeb();
        System.out.println("开始生成代码文件...DONE");

        System.out.println("生成项目文件...DONE");
        System.out.println("完成操作...");
        System.out.println("请到以下地址复制文件..." + CONF_DIR_PATH);
    }

    private void makeWeb() throws IOException {
        makeWebPomXml();
        makeWebSrc();
    }

    private void makeWebSrc() throws IOException {
        String srcPath = rootSrcPath(rootWebDirPath,"java") + packageToPath(rootPackage);
        String resourcePath = rootSrcPath(rootWebDirPath,"resources");
        new File(srcPath).mkdirs();
        new File(resourcePath).mkdirs();
        makeController(srcPath);
        makeRemote(srcPath);
        makeInterceptor(srcPath);
        makeConfig(srcPath);
        if(needDubbo){
            makeDubbo(srcPath);
        }
        if(needActivemq){
            makeActivemq(srcPath);
        }

        String start = AutoCodeUtils.readResource("newProject/newWeb/start.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        String fileName = wordFirstUp(webName) +"WebApplication";
        param.put("webAppName",fileName);
        start = AutoCodeUtils.replacePlaceHolder(start,param);
        AutoCodeUtils.makeFile(srcPath,fileName+".java",start);

        makeApplication(resourcePath);

        makeProperteis(resourcePath);

        makeBootstrap(resourcePath);

        makeLogback(resourcePath);
    }

    private void makeConfig(String srcPath) throws IOException {
        String path = srcPath + File.separator +"config";
        new File(path).mkdir();
        String interceptorConfiguration = AutoCodeUtils.readResource("newProject/newWeb/interceptorConfiguration.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        if(needAuth){
            param.put("importAuthClass","import "+rootPackage+".interceptor.AuthorityInterceptor;\n");
            param.put("importAuth","        registry.addInterceptor(new AuthorityInterceptor()).addPathPatterns(\"/security/**\");\n");
        }else{
            param.put("importAuthClass","");
            param.put("importAuth","");
        }
        interceptorConfiguration = AutoCodeUtils.replacePlaceHolder(interceptorConfiguration,param);
        AutoCodeUtils.makeFile(path,"InterceptorConfiguration.java",interceptorConfiguration);

        String swagger = AutoCodeUtils.readResource("newProject/newWeb/swagger2Config.new");
        swagger = AutoCodeUtils.replacePlaceHolder(swagger,param);
        AutoCodeUtils.makeFile(path,"Swagger2Config.java",swagger);

        String swaggerTag = AutoCodeUtils.readResource("newProject/newWeb/swaggerTag.new");
        swaggerTag = AutoCodeUtils.replacePlaceHolder(swaggerTag,param);
        AutoCodeUtils.makeFile(path,"ApiSwaggerTags.java",swaggerTag);

        if(needAuth){
            String auth = AutoCodeUtils.readResource("newProject/newWeb/authorityAnnotation.new");
            auth = AutoCodeUtils.replacePlaceHolder(auth,param);
            AutoCodeUtils.makeFile(path,"AuthorityAnnotation.java",auth);

            String authEnum = AutoCodeUtils.readResource("newProject/newWeb/authorityAnnotationEnums.new");
            authEnum = AutoCodeUtils.replacePlaceHolder(authEnum,param);
            AutoCodeUtils.makeFile(path,"AuthorityAnnotationEnums.java",authEnum);
        }
    }

    private void makeRemote(String srcPath) throws IOException {
        String path = srcPath + File.separator +"remote";
        new File(path).mkdir();
        String remote = AutoCodeUtils.readResource("newProject/newWeb/firstRemote.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        remote = AutoCodeUtils.replacePlaceHolder(remote,param);
        AutoCodeUtils.makeFile(path,"FirstRemote.java",remote);
    }

    private void makeActivemq(String srcPath) throws IOException {
        String path = srcPath + File.separator +"mq";
        new File(path).mkdir();
        String firstListenerQueue = AutoCodeUtils.readResource("newProject/module/firstListenerQueue.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        firstListenerQueue = AutoCodeUtils.replacePlaceHolder(firstListenerQueue,param);
        AutoCodeUtils.makeFile(path,"FirstListenerQueue.java",firstListenerQueue);

        String configPath = srcPath + File.separator +"config";
        new File(configPath).mkdir();
        String activeConfiguration = AutoCodeUtils.readResource("newProject/module/activeConfiguration.new");
        activeConfiguration = AutoCodeUtils.replacePlaceHolder(activeConfiguration,param);
        AutoCodeUtils.makeFile(configPath,"ActiveConfiguration.java",activeConfiguration);
    }

    private void makeProperteis(String resourcePath) throws IOException {
        String properties = AutoCodeUtils.readResource("newProject/newWeb/properties.new");
        Map<String,String> param = CommonMapUtil.NEW();
        param.put("activemq-prop",needActivemq? AutoCodeUtils.readResource("newProject/module/props/activemq-prop.new"):"");
        param.put("rabbitmq-prop",needRabbitmq? AutoCodeUtils.readResource("newProject/module/props/rabbitmq-prop.new"):"");
        param.put("dubbo-prop",needDubbo? AutoCodeUtils.readResource("newProject/module/props/dubbo-prop.new"):"");
        param.put("redis-prop",needRedis? AutoCodeUtils.readResource("newProject/module/props/redis-prop.new"):"");
        properties = AutoCodeUtils.replacePlaceHolder(properties,param);
        param.put("serviceName",webDir);
        param.put("projectName",projectName);
        param.put("hasRedis",needRedis?"":"basic.redis.on=false");
        properties = AutoCodeUtils.replacePlaceHolder(properties,param);
        AutoCodeUtils.makeFile(resourcePath,"application.properties",properties);
    }

    private void makeLogback(String resourcePath) throws IOException {
        String logBack = AutoCodeUtils.readResource("newProject/newWeb/logback.new");
        String rootDir = projectName + (StringUtils.isNotEmpty(bizName)?("/"+bizName):"");
        Map<String,String> param = CommonMapUtil.NEW("path",rootDir+"/webs/"+webDir);
        logBack = AutoCodeUtils.replacePlaceHolder(logBack,param);
        AutoCodeUtils.makeFile(resourcePath,"logback.xml",logBack);
    }

    private void makeApplication(String resourcePath) throws IOException {
        String application = AutoCodeUtils.readResource("newProject/module/application.new");
        Map<String,String> param = CommonMapUtil.NEW("serviceName",webDir);
        application = AutoCodeUtils.replacePlaceHolder(application,param);
        AutoCodeUtils.makeFile(resourcePath,"application.yml",application);
    }

    private void makeBootstrap(String resourcePath) throws IOException {
        String bootstrap = AutoCodeUtils.readResource("newProject/module/bootstrap.new");
        Map<String,String> param = CommonMapUtil.NEW("serviceName",webDir);
        bootstrap = AutoCodeUtils.replacePlaceHolder(bootstrap,param);
        AutoCodeUtils.makeFile(resourcePath,"bootstrap.yml",bootstrap);
    }

    private void makeDubbo(String srcPath) throws IOException {
        String configPath = srcPath + File.separator +"config";
        new File(configPath).mkdir();

        String dubboConfiguration = AutoCodeUtils.readResource("newProject/module/dubboConfiguration.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        dubboConfiguration = AutoCodeUtils.replacePlaceHolder(dubboConfiguration,param);
        AutoCodeUtils.makeFile(configPath,"DubboConfiguration.java",dubboConfiguration);
    }


    private void makeInterceptor(String srcPath) throws IOException {
        String path = srcPath + File.separator +"interceptor";
        new File(path).mkdir();
        String dataSourceKey = webDir.toUpperCase().replaceAll("-","_");
        String contextInterceptor = AutoCodeUtils.readResource("newProject/module/contextInterceptor.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        param.put("dataSourceKey",dataSourceKey);
        contextInterceptor = AutoCodeUtils.replacePlaceHolder(contextInterceptor,param);
        AutoCodeUtils.makeFile(path,"ContextInterceptor.java",contextInterceptor);

        String swagger = AutoCodeUtils.readResource("newProject/newWeb/swaggerLoginInterceptor.new");
        swagger = AutoCodeUtils.replacePlaceHolder(swagger,param);
        AutoCodeUtils.makeFile(path,"SwaggerLoginInterceptor.java",swagger);

        if(needAuth){
            String auth = AutoCodeUtils.readResource("newProject/newWeb/authorityInterceptor.new");
            auth = AutoCodeUtils.replacePlaceHolder(auth,param);
            AutoCodeUtils.makeFile(path,"AuthorityInterceptor.java",auth);
        }
    }

    private void makeController(String srcPath) throws IOException {
        String path = srcPath + File.separator +"controller";
        new File(path).mkdir();
        String openApiPath = path + File.separator +"openapi";
        new File(openApiPath).mkdir();
        new File(path + File.separator +"security").mkdir();

        String webBase = AutoCodeUtils.readResource("newProject/newWeb/webBaseController.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        webBase = AutoCodeUtils.replacePlaceHolder(webBase,param);
        AutoCodeUtils.makeFile(path,"WebBaseController.java",webBase);

        String first = AutoCodeUtils.readResource("newProject/newWeb/firstController.new");
        if(needAuth){
            param.put("importAuthClass","import "+rootPackage+".config.AuthorityAnnotation;\n" +
                    "import "+rootPackage+".config.AuthorityAnnotationEnums;\n");
            param.put("authAnnotation","@AuthorityAnnotation(AuthorityAnnotationEnums.ADMIN)");
        }else{
            param.put("importAuthClass","");
            param.put("authAnnotation","");
        }
        first = AutoCodeUtils.replacePlaceHolder(first,param);
        AutoCodeUtils.makeFile(openApiPath,"FirstController.java",first);
    }

    private void makeWebPomXml() throws IOException {
        String pom = AutoCodeUtils.readResource("newProject/newWeb/pom.new");
        Map<String,String> replace = new HashMap<>();
        replace.put("artifactId",webDir);
        replace.put("groupId",groupId);
        replace.put("parent-version", AutoCodeUtils.PARENT_VERSION);
        replace.put("redis-pom",needRedis? AutoCodeUtils.readResource("newProject/module/poms/redis-pom.new"):"");
        replace.put("dubbo-pom",needDubbo? AutoCodeUtils.readResource("newProject/module/poms/dubbo-pom.new"):"");
        replace.put("activemq-pom",needActivemq? AutoCodeUtils.readResource("newProject/module/poms/activemq-pom.new"):"");
        replace.put("rabbitmq-pom",needRabbitmq? AutoCodeUtils.readResource("newProject/module/poms/rabbitmq-pom.new"):"");
        pom = AutoCodeUtils.replacePlaceHolder(pom,replace);
        AutoCodeUtils.makeFile(rootWebDirPath,"pom.xml",pom);
    }

    private void makeRoot() {
        File root = new File(CONF_DIR_PATH);
        if (!root.exists()) {
            root.mkdir();
        }
        File rootDirFile = new File(rootWebDirPath);
        if (rootDirFile.exists()) {
            rootDirFile.delete();
        }
        rootDirFile.mkdir();
    }

    @Override
    public String toString() {
        return "NewWebProjectHelper{" +
                "projectName='" + projectName + '\'' +
                ", bizName='" + bizName + '\'' +
                ", webName='" + webName + '\'' +
                '}';
    }

    public void setNeedDubbo(boolean needDubbo) {
        this.needDubbo = needDubbo;
    }

    public void setNeedRedis(boolean needRedis) {
        this.needRedis = needRedis;
    }

    public void setNeedActivemq(boolean needActivemq) {
        this.needActivemq = needActivemq;
    }

    public void setNeedAuth(boolean needAuth) {
        this.needAuth = needAuth;
    }

    public void setNeedRabbitmq(boolean needRabbitmq) {
        this.needRabbitmq = needRabbitmq;
    }
}
